Python中列表list使用注意点(从引用传递,可变对象,不可变对象引申)

您所在的位置:网站首页 python 引用对象 Python中列表list使用注意点(从引用传递,可变对象,不可变对象引申)

Python中列表list使用注意点(从引用传递,可变对象,不可变对象引申)

2024-05-27 23:38| 来源: 网络整理| 查看: 265

python中的引用传递 首先必须理解的是,python中一切的传递都是引用(地址),无论是赋值还是函数调用,不存在值传递。

可变对象和不可变对象 python变量保存的是对象的引用,这个引用指向堆内存里的对象,在堆中分配的对象分为两类,一类是可变对象,一类是不可变对象。不可变对象的内容不可改变,保证了数据的不可修改(安全,防止出错),同时可以使得在多线程读取的时候不需要加锁。

不可变对象(变量指向的内存的中的值不能够被改变) 当更改该对象时,由于所指向的内存中的值不可改变,所以会把原来的值复制到新的空间,然后变量指向这个新的地址。 python中数值类型(int和float),布尔型bool,字符串str,元组tuple都是不可变对象。

a = 1 print id(a) # 40133000L,整数1放在了地址为40133000L的内存中,a变量指向这个地址。 a += 1 print id(a) # 40132976L,整数int不可改变,开辟新空间存放加1后的int,a指向这个新空间。

可变对象(变量指向的内存的中的值能够被改变) 当更改该对象时,所指向的内存中的值直接改变,没有发生复制行为。 python中列表list,字典dict,集合set都是可变对象。包括自定义的类对象也是可变对象。

a = [1,2,3] print id(a) # 44186120L。 a += [4,5] # 相当于调用了a.extend([4,5]) print id(a) # 44186120L,列表list可改变,直接改变指向的内存中的值,没开辟新空间。 a = a + [7,8] # 直接+和+=并不等价,使用+来操作list时,得到的是新的list,不指向原空间。 print id(a) # 44210632L def f(default_arg=[]): default_arg.append('huihui') f() # ['huihui'] f() # ['huihui', 'huihui'] # 函数默认的可变参数并不会每次重新初始化,而是使用上次的作为默认值。 f([]) # ['huihui'] # 自行传入参数即可

不可变对象的编译时驻留(类似java的常量池) int的驻留:-5到256之间的整数都会进行驻留,再次定义的变量地址不变,为什么是-5到256呢,这是解释器决定的,依赖于具体实现。 str的驻留:只包含字母,数字,下划线的字符串会驻留;长度为0或1的会驻留;

a = -5 b = -5 a is b # True,-5到256之间的整数,驻留(直觉上这部分数据会频繁调用,驻留可以节省资源)

List注意点

a = [1,2,3] b = a a is b # True,因为按引用传递,a和b存的地址(引用)是一样的,改变b相当于改变a。 b = a[:] a is b # False,想使用list的值却不想修改原list时可以使用切片[:]拷贝一份到新空间。 a = [1,2,3] id(a) # 140376329323528 a = [1,2,3] id(a) # 140376359286920,两次定义相同的list,但是其地址并不相同,会创造新对象 a = [1,2,3] id(a) # 140376329323528 a[:] = [1,2,3] id(a) # 140376329323528,因为a[:]切片创建的是新空间,对新空间赋值不影响旧空间a,所以a的地址跟原来一致。 a =[ [0]*2 ]* 2 # 以这种方式创建一个二维list,此时a为[[0,0],[0,0]]。 a[0] is a[1] # True,这种创建方法的机制是复制list,所以2个list其实是同一个list。 a[0][0] = 1 # 改变第一个list时第二个list也改变,此时a为[[1,0],[1,0]]。 a[0] += [1] # 改变第一个list时第二个list也改变,此时a为[[1,0,1],[1,0,1]]。+=相当于extend,对list进行原地修改。 a[0] = a[0] + [1] # 改变第一个list时,第二个list不改变,此时a为[[1,0,1,1],[1,0,1]]。因为不是原地改变,而是创建了新list,然后给原来的引用赋了新值。 a[0] = [1,2] # a[0]指向创建的新list[1,2]。此时a[1]不变,a为[[1,2],[1,0,1]]。同样是给a[0]赋值了新的list[1,2],不会影响到a[1]。 a = [0] * 2 a[0] = 1 # 一维数组不同,这并不会将a[1]也同时改变 a = [[0]*2 for _ in range(2)] # 相对正确的创建方式,这样创建的二维list,改变a[0]并不会影响a[1] a[0] is a[1] # False a = [ []*1000 ] # 同理,这么定义返回的是[],并不能得到含有1000个空list的list(直觉误区) a = [ [] for _ in range(1000) ] # 正确的定义方式

参考文献:python中的引用传递,可变对象,不可变对象,list注意点 - PilgrimHui - 博客园 (cnblogs.com)



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3